﻿using Api.Models;
using SqlSugar;
using System.ComponentModel.DataAnnotations;
using System.Security.Cryptography;

namespace Api.Services
{

    public class RegisterRequest
    {
        [Required]
        public required string Username { get; set; }

        [Required]
        public required string Password { get; set; }
        [Required]
        public required string Email { get; set; }
    }

    public class LoginRequest
    {
        [Required]
        public required string Password { get; set; }
        [Required]
        public required string Email { get; set; }
    }


    public class AuthResponse
    {
        public int UserId { get; set; }
        public string? Username { get; set; }
        public string? Email { get; set; }
        public string? Token { get; set; }
        public DateTime? ExpiresAt { get; set; }
    }

    public interface IAuthService
    {
        Task<User> Register(string username, string email, string password);
        Task<AuthResponse> Login(string email, string password);

        Task<bool> VerifyEmail(string token);

        Task<bool> UserExists(string email);
    }

    public class AuthService : IAuthService
    {
        private readonly ISqlSugarClient _client;
        private readonly ITokenService _tokenService;

        public AuthService(ISqlSugarClient client, ITokenService tokenService)
        {
            _client = client;
            _tokenService = tokenService;
        }

        public async Task<User> Register(string username, string email, string password)
        {
            if (await UserExists(email))
                throw new Exception("该邮箱已被注册");

            CreatePasswordHash(password, out byte[] passwordHash, out byte[] passwordSalt);

            var verificationToken = Convert.ToBase64String(RandomNumberGenerator.GetBytes(64));

            var user = new User
            {
                Username = username,
                Email = email,
                PasswordHash = passwordHash,
                PasswordSalt = passwordSalt,
                VerificationToken = verificationToken,
                UpdatedAt = DateTime.UtcNow
            };

            await _client.Insertable<User>(user).ExecuteCommandAsync();

            // 发送验证邮件 暂时不验证邮箱
            //await _emailService.SendVerificationEmail(email, verificationToken);

            return user;
        }

        public async Task<AuthResponse> Login(string email, string password)
        {
            var user = await _client.Queryable<User>().FirstAsync(u => u.Email == email);

            if (user == null || !VerifyPasswordHash(password, user.PasswordHash, user.PasswordSalt))
                throw new ApplicationException("邮箱或密码错误");

            TokenInfo? token = _tokenService.GenerateToken(user);

            return new AuthResponse
            {
                UserId = user.Id,
                Username = user.Username,
                Email = user.Email,
                Token = token.Token,
                ExpiresAt = token.ExpiresAt
            };
        }

        public async Task<bool> VerifyEmail(string token)
        {
            User? user = await _client.Queryable<User>().FirstAsync(u => u.VerificationToken == token);

            if (user == null)
                return false;

            user.EmailVerified = true;
            user.VerificationToken = null;
            user.UpdatedAt = DateTime.UtcNow;

            await _client.Updateable<User>(user).ExecuteCommandAsync();

            return true;
        }

        public async Task<bool> UserExists(string email)
        {
            return await _client.Queryable<User>().AnyAsync(u => u.Email == email);
        }


        private void CreatePasswordHash(string password, out byte[] passwordHash, out byte[] passwordSalt)
        {
            using var hmac = new HMACSHA512();
            passwordSalt = hmac.Key;
            passwordHash = hmac.ComputeHash(System.Text.Encoding.UTF8.GetBytes(password));
        }

        private bool VerifyPasswordHash(string password, byte[]? passwordHash, byte[]? passwordSalt)
        {
            if(passwordHash == null||passwordSalt==null) return false;
            using var hmac = new HMACSHA512(passwordSalt);
            var computedHash = hmac.ComputeHash(System.Text.Encoding.UTF8.GetBytes(password));
            return computedHash.SequenceEqual(passwordHash);
        }


    }
}
